#pragma once
#include "../Thread/TaskGraph.h"
#include "../Core/CoreGlobals.h"
#include "Texture/RHITexture.h"
#include "Tradition/RHIPipeline.h"
#include "Tradition/RHIRenderPass.h"
#include "Raytracing/AccelerationStructureGeometry.h"
#include "RenderState.h"

/** The parent class of commands stored in the rendering command queue. */
template<typename TSTR, typename LAMBDA>
class RenderGraphTask
{
public:

	/** Creates and initializes a new instance. */
	RenderGraphTask(LAMBDA&& lambda) : mLambda(std::forward<LAMBDA>(lambda))
	{ }

	/** Performs the actual task. */
	void DoTask(const GraphEventRef& myCompletionGraphEvent)
	{
		VkCommandBuffer commandBuffer = GRenderState->GetImmediateCommandBuffer();
		mLambda(commandBuffer);
	}

	/** Returns the name of the thread that this task should run on. */
	uint32 GetDesiredThreadId()
	{
		return GRenderThreadId;
	}

	/** Returns the name of the graph to generate graph map */
	const char* GetName() { return TSTR::GetName(); }

private:

	/** The function to execute on the Task Graph. */
	LAMBDA mLambda;
};


template<typename TSTR, typename LAMBDA>
void EnqueueUniqueRenderCommand(LAMBDA&& lambda)
{
	typedef RenderGraphTask<TSTR, LAMBDA> EURCType;

	if (IsInRenderThread())
	{
		VkCommandBuffer commandBuffer = GRenderState->GetImmediateCommandBuffer();
		lambda(commandBuffer);
	}
	else
	{
		GraphTask<EURCType>::CreateTask().ConstructAndDispatchWhenReady(std::forward<LAMBDA>(lambda));
	}
}


#define ENQUEUE_RENDER_COMMAND(Type) \
	struct Type##Graph \
	{  \
		static const char* GetName() { return #Type; } \
	}; \
	EnqueueUniqueRenderCommand<Type##Graph>



template<typename LAMBDA>
void EnqueueUniqueRenderCommand(LAMBDA& Lambda)
{
	static_assert(sizeof(LAMBDA) == 0, "EnqueueUniqueRenderCommand enforces use of rvalue and therefore move to avoid an extra copy of the Lambda");
}